package services

import (
	"archive/zip"
	"bytes"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"
)

// DocxService DOCX 文件处理服务
type DocxService struct {
}

// NewDocxService 创建 DOCX 服务
func NewDocxService() *DocxService {
	return &DocxService{}
}

// ExtractVariablesFromDocx 从 DOCX 文件中提取变量
func (s *DocxService) ExtractVariablesFromDocx(docxPath string) ([]string, error) {
	// 读取 DOCX 文件
	data, err := os.ReadFile(docxPath)
	if err != nil {
		return nil, err
	}

	// DOCX 是一个 ZIP 文件，包含 word/document.xml
	zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		return nil, err
	}

	var documentXML []byte
	for _, file := range zipReader.File {
		if file.Name == "word/document.xml" {
			rc, err := file.Open()
			if err != nil {
				return nil, err
			}
			defer rc.Close()
			documentXML, err = io.ReadAll(rc)
			if err != nil {
				return nil, err
			}
			break
		}
	}

	if documentXML == nil {
		return nil, fmt.Errorf("找不到 word/document.xml")
	}

	// 提取所有 {{变量名}} 格式的变量（支持中文）
	re := regexp.MustCompile(`\{\{([^}]+)\}\}`)
	matches := re.FindAllStringSubmatch(string(documentXML), -1)

	variables := make(map[string]bool)
	for _, match := range matches {
		if len(match) > 1 {
			varName := strings.TrimSpace(match[1])
			if varName != "" {
				variables[varName] = true
			}
		}
	}

	var result []string
	for v := range variables {
		result = append(result, v)
	}
	
	// 确保返回的是数组而不是 nil
	if result == nil {
		result = []string{}
	}

	return result, nil
}

// FillDocx 填充 DOCX 模板
func (s *DocxService) FillDocx(templatePath string, data map[string]string, outputPath string) error {
	// 读取原始 DOCX 文件
	docxData, err := os.ReadFile(templatePath)
	if err != nil {
		return err
	}

	// 打开 ZIP 文件
	zipReader, err := zip.NewReader(bytes.NewReader(docxData), int64(len(docxData)))
	if err != nil {
		return err
	}

	// 创建新的 ZIP 文件
	buf := new(bytes.Buffer)
	zipWriter := zip.NewWriter(buf)

	// 遍历原始 ZIP 中的所有文件
	for _, file := range zipReader.File {
		// 读取文件内容
		rc, err := file.Open()
		if err != nil {
			return err
		}

		fileData, err := io.ReadAll(rc)
		rc.Close()
		if err != nil {
			return err
		}

		// 如果是 document.xml，进行变量替换
		if file.Name == "word/document.xml" {
			content := string(fileData)
			for key, value := range data {
				placeholder := "{{" + key + "}}"
				content = strings.ReplaceAll(content, placeholder, escapeXML(value))
			}
			fileData = []byte(content)
		}

		// 写入新文件
		w, err := zipWriter.Create(file.Name)
		if err != nil {
			return err
		}
		_, err = w.Write(fileData)
		if err != nil {
			return err
		}
	}

	err = zipWriter.Close()
	if err != nil {
		return err
	}

	// 保存新文件
	return os.WriteFile(outputPath, buf.Bytes(), 0644)
}

// escapeXML 转义 XML 特殊字符
func escapeXML(s string) string {
	s = strings.ReplaceAll(s, "&", "&amp;")
	s = strings.ReplaceAll(s, "<", "&lt;")
	s = strings.ReplaceAll(s, ">", "&gt;")
	s = strings.ReplaceAll(s, "\"", "&quot;")
	s = strings.ReplaceAll(s, "'", "&apos;")
	return s
}

// GetDocxText 获取 DOCX 文件的文本内容（用于预览）
func (s *DocxService) GetDocxText(docxPath string) (string, error) {
	data, err := os.ReadFile(docxPath)
	if err != nil {
		return "", err
	}

	zipReader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		return "", err
	}

	for _, file := range zipReader.File {
		if file.Name == "word/document.xml" {
			rc, err := file.Open()
			if err != nil {
				return "", err
			}
			defer rc.Close()

			var doc Document
			decoder := xml.NewDecoder(rc)
			err = decoder.Decode(&doc)
			if err != nil {
				return "", err
			}

			// 提取所有文本
			var text strings.Builder
			extractText(&doc, &text)
			return text.String(), nil
		}
	}

	return "", fmt.Errorf("找不到 word/document.xml")
}

// Document XML 文档结构（简化版）
type Document struct {
	XMLName xml.Name `xml:"document"`
	Body    Body     `xml:"body"`
}

type Body struct {
	Paragraphs []Paragraph `xml:"p"`
}

type Paragraph struct {
	Runs []Run `xml:"r"`
}

type Run struct {
	Text []Text `xml:"t"`
}

type Text struct {
	Content string `xml:",chardata"`
}

func extractText(doc *Document, builder *strings.Builder) {
	for _, p := range doc.Body.Paragraphs {
		for _, r := range p.Runs {
			for _, t := range r.Text {
				builder.WriteString(t.Content)
			}
		}
		builder.WriteString("\n")
	}
}

